home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
gnu
/
oleo-1_4.lha
/
oleo-1.4
/
decompile.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-29
|
19KB
|
845 lines
/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.
This file is part of Oleo, the GNU Spreadsheet.
Oleo is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Oleo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "global.h"
#include "decompile.h"
#include "eval.h"
#include "cell.h"
#include "io-utils.h"
struct pr_node
{
int tightness;
int len;
char string[1];
};
static VOIDSTAR save_decomp;
static CELLREF decomp_row;
static CELLREF decomp_col;
/* These #defines are so that we don't have to duplicate code below */
/* JF: now obsolete, and should be trashed. */
#define F0 a0?"@%s()":"%s()"
#define F1 a0?"@%s(%s)":"%s(%s)"
#define F2 a0?"@%s(%s, %s)":"%s(%s, %s)"
#define F3 a0?"@%s(%s, %s, %s)":"%s(%s, %s, %s)"
#define F4 a0?"@%s(%s, %s, %s, %s)":"%s(%s, %s, %s, %s)"
#define FN1 a0?"@%s(%s":"%s(%s"
/* We decompile things with these wierd node-things. It's ugly, but it works.
*/
#ifdef __STDC__
static struct pr_node *
n_alloc (int size, int tightness, char *fmt,...)
#else
static struct pr_node *
n_alloc (size, tightness, fmt, va_alist)
int size;
int tightness;
char *fmt;
va_dcl
#endif
{
struct pr_node *ret;
va_list args;
ret = ck_malloc (sizeof (struct pr_node) + size + 1);
ret->len = size;
ret->tightness = tightness;
var_start (args, fmt);
vsprintf (ret->string, fmt, args);
va_end (args);
return ret;
}
#define n_free(x) free(x)
static struct pr_node *
byte_decompile (expr)
unsigned char *expr;
{
unsigned char byte;
double tmp_flt;
long tmp_lng;
char *tmp_str;
struct var *v;
unsigned long_skp;
unsigned char save_val;
unsigned jumpto;
struct pr_node *new = 0;
int pri;
int aso;
char *chr;
static struct pr_node **the_line;
static int line_alloc;
static struct pr_node **c_node;
struct function *f;
if (!the_line)
{
the_line = (struct pr_node **) ck_malloc (20 * sizeof (struct pr_node *));
line_alloc = 20;
c_node = the_line;
}
#ifdef TEST
if (!expr)
panic ("No expression to decompile");
#endif
next_byte:
byte = *expr++;
if (byte < USR1)
f = &the_funs[byte];
else if (byte < SKIP)
{
tmp_lng = *expr++;
f = &usr_funs[byte - USR1][tmp_lng];
}
else
f = &skip_funs[byte - SKIP];
if (f->fn_argn & X_J)
jumpto = *expr++;
else if (f->fn_argn & X_JL)
{
jumpto = expr[0] + ((unsigned) (expr[1]) << 8);
expr += 2;
}
else
jumpto = 0;
switch (GET_COMP (f->fn_comptype))
{
case C_IF:
if (expr[jumpto - 2] != SKIP)
{
long_skp = 1;
save_val = expr[jumpto - 3];
expr[jumpto - 3] = 0;
}
else
{
long_skp = 0;
save_val = expr[jumpto - 2];
expr[jumpto - 2] = 0;
}
c_node[0] = byte_decompile (expr);
c_node++;
if (long_skp)
{
expr[jumpto - 3] = save_val;
expr += jumpto;
jumpto = expr[-2] + ((unsigned) (expr[-1]) << 8);
}
else
{
expr[jumpto - 2] = save_val;
expr += jumpto;
jumpto = expr[-1];
}
save_val = expr[jumpto];
expr[jumpto] = 0;
c_node[0] = byte_decompile (expr);
c_node -= 2;
expr[jumpto] = save_val;
expr += jumpto;
if (byte == IF || byte == IF_L)
{
if (c_node[0]->tightness <= 1)
new = n_alloc (8 + c_node[0]->len + c_node[1]->len + c_node[2]->len,
1,
"(%s) ? %s : %s", c_node[0]->string, c_node[1]->string, c_node[2]->string);
else
new = n_alloc (6 + c_node[0]->len + c_node[1]->len + c_node[2]->len,
1,
"%s ? %s : %s", c_node[0]->string, c_node[1]->string, c_node[2]->string);
}
else
new = n_alloc (6 + c_node[0]->len + c_node[1]->len + c_node[2]->len + strlen (f->fn_str),
1000,
F3, f->fn_str, c_node[0]->string, c_node[1]->string, c_node[2]->string);
n_free (c_node[0]);
n_free (c_node[1]);
n_free (c_node[2]);
break;
case C_ANDOR:
save_val = expr[jumpto];
expr[jumpto] = 0;
c_node[0] = byte_decompile (expr);
expr[jumpto] = save_val;
expr += jumpto;
c_node++;
if (ISINFIX (f->fn_comptype))
{
pri = GET_IN (f->fn_comptype);
aso = GET_ASO (f->fn_comptype);
chr = f->fn_str;
goto do_infix;
}
else
goto do_fn2;
case C_STR:
tmp_str = backslash_a_string ((char *) expr + jumpto, 1);
new = n_alloc (strlen (tmp_str) + 1,
1000,
tmp_str);
break;
case C_CELL:
{
int num1, num2;
char *str;
CELLREF row, col;
row = GET_ROW (expr);
col = GET_COL (expr);
expr += EXP_ADD;
if (a0)
{
new = n_alloc (30, 1000, f->fn_str, col_to_str (col), row);
}
else
{
if (byte & ROWREL)
{
num1 = row - decomp_row;
if (byte & COLREL)
{
num2 = col - decomp_col;
if (row == decomp_row && col == decomp_col)
str = "rc";
else if (row == decomp_row)
{
str = "rc[%+d]";
num1 = num2;
}
else if (col == decomp_col)
str = "r[%+d]c";
else
str = "r[%+d]c[%+d]";
}
else if (row == decomp_row)
{
str = "rc%u";
num1 = num2 = col;
}
else
{
str = "r[%+d]c%u";
num2 = col;
}
}
else if (byte & COLREL)
{
num1 = row;
num2 = col - decomp_col;
if (col == decomp_col)
str = "r%uc";
else
str = "r%uc[%+d]";
}
else
{
str = "r%uc%u";
num1 = row;
num2 = col;
}
new = n_alloc (30, 1000, str, num1, num2);
}
new->len = strlen (new->string);
}
break;
case C_RANGE:
{
char tmprbuf[40];
char tmpcbuf[40];
struct rng rng;
GET_RNG (expr, &rng);
expr += EXP_ADD_RNG;
if (a0)
new = n_alloc (40, 1000, f->fn_str, col_to_str (rng.lc), rng.lr, col_to_str (rng.hc), rng.hr);
else
{
/* Check for special cases */
if (rng.lr == rng.hr && ((byte & LRREL) ? 1 : 0) == ((byte & HRREL) ? 1 : 0))
{
if (byte & LRREL)
{
if (rng.lr == decomp_row)
{
tmprbuf[0] = 'r';
tmprbuf[1] = '\0';
}
else
(void) sprintf (tmprbuf, "r[%+d]", rng.lr - decomp_row);
}
else
sprintf (tmprbuf, "r%u", rng.lr);
}
else if ((byte & LRREL) && (byte & HRREL))
{
int r1, r2, rtmp;
r1 = rng.lr - decomp_row;
r2 = rng.hr - decomp_row;
if (r1 < r2)
rtmp = r1, r1 = r2, r2 = rtmp;
(void) sprintf (tmprbuf, "r[%+d:%+d]", r1, r2);
}
else if ((byte & LRREL))
(void) sprintf (tmprbuf, "r[%+d]:%u", rng.lr - decomp_row, rng.hr);
else if (byte & HRREL)
(void) sprintf (tmprbuf, "r%u:[%+d]", rng.lr, rng.hr - decomp_row);
else if (rng.lr < rng.hr)
(void) sprintf (tmprbuf, "r%u:%u", rng.lr, rng.hr);
else
(void) sprintf (tmprbuf, "r%u:%u", rng.hr, rng.lr);
if (rng.lc == rng.hc && ((byte & LCREL) ? 1 : 0) == ((byte & HCREL) ? 1 : 0))
{
if (byte & LCREL)
{
if (rng.lc == decomp_col)
{
tmpcbuf[0] = 'c';
tmpcbuf[1] = '\0';
}
else
sprintf (tmpcbuf, "c[%+d]", rng.lc - decomp_col);
}
else
sprintf (tmpcbuf, "c%u", rng.lc);
}
else if ((byte & LCREL) && (byte & HCREL))
{
int c1, c2, ctmp;
c1 = rng.lc - decomp_col;
c2 = rng.hc - decomp_col;
if (c1 < c2)
ctmp = c1, c1 = c2, c2 = ctmp;
(void) sprintf (tmpcbuf, "c[%+d:%+d]", c1, c2);
}
else if ((byte & LCREL))
(void) sprintf (tmpcbuf, "c[%+d]:%u", rng.lc - decomp_col, rng.hc);
else if (byte & HCREL)
(void) sprintf (tmpcbuf, "c%u:[%+d]", rng.lc, rng.hc - decomp_col);
else if (rng.lc < rng.hc)
(void) sprintf (tmpcbuf, "c%u:%u", rng.lc, rng.hc);
else
(void) sprintf (tmpcbuf, "c%u:%u", rng.hc, rng.lc);
new = n_alloc (40, 1000, "%s%s", tmprbuf, tmpcbuf);
}
new->len = strlen (new->string);
}
break;
case C_CONST:
new = n_alloc (strlen (f->fn_str) + 1, 1000, f->fn_str);
break;
case C_FN0:
case C_FN0X:
case C_FN0 | C_T:
new = n_alloc (strlen (f->fn_str) + 3,
1000,
F0,
f->fn_str);
break;
case C_FN1:
--c_node;
new = n_alloc (c_node[0]->len + strlen (f->fn_str) + 3,
1000,
F1, f->fn_str, c_node[0]->string);
n_free (*c_node);
break;
case C_UNA:
--c_node;
if (c_node[0]->tightness < 9)
{
new = n_alloc (3 + c_node[0]->len,
9,
"%s(%s)", f->fn_str, c_node[0]->string);
}
else
{
new = n_alloc (1 + c_node[0]->len,
9,
"%s%s", f->fn_str, c_node[0]->string);
}
n_free (*c_node);
break;
case C_INF:
pri = GET_IN (f->fn_comptype);
aso = GET_ASO (f->fn_comptype);
chr = f->fn_str;
do_infix:
c_node -= 2;
if (c_node[0]->tightness < pri || (c_node[0]->tightness == pri && aso != 1))
{
if (c_node[1]->tightness < pri || (c_node[1]->tightness == pri && aso != -1))
new = n_alloc (7 + c_node[0]->len + c_node[1]->len,
pri,
"(%s) %s (%s)", c_node[0]->string, chr, c_node[1]->string);
else
new = n_alloc (5 + c_node[0]->len + c_node[1]->len,
pri,
"(%s) %s %s", c_node[0]->string, chr, c_node[1]->string);
}
else if (c_node[1]->tightness < pri || (c_node[1]->tightness == pri && aso != -1))
new = n_alloc (5 + c_node[0]->len + c_node[1]->len,
pri,
"%s %s (%s)", c_node[0]->string, chr, c_node[1]->string);
else
new = n_alloc (3 + c_node[0]->len + c_node[1]->len,
pri,
"%s %s %s", c_node[0]->string, chr, c_node[1]->string);
n_free (c_node[0]);
n_free (c_node[1]);
break;
case C_FN2:
do_fn2:
c_node -= 2;
new = n_alloc (c_node[0]->len + c_node[1]->len + strlen (f->fn_str) + 5,
1000,
F2, f->fn_str, c_node[0]->string, c_node[1]->string);
n_free (c_node[0]);
n_free (c_node[1]);
break;
case C_FN3:
c_node -= 3;
new = n_alloc (c_node[0]->len + c_node[1]->len + c_node[2]->len + strlen (f->fn_str) + 7,
1000,
F3,
f->fn_str,
c_node[0]->string,
c_node[1]->string,
c_node[2]->string);
n_free (c_node[0]);
n_free (c_node[1]);
n_free (c_node[2]);
break;
case C_FNN:
aso = *expr++;
c_node -= aso;
if (aso == 1)
new = n_alloc (3 + c_node[0]->len + strlen (f->fn_str),
1000,
F1, f->fn_str, c_node[0]->string);
else
{
new = n_alloc (2 + c_node[0]->len + strlen (f->fn_str),
1000,
FN1, f->fn_str, c_node[0]->string);
--aso;
for (pri = 1; pri < aso; pri++)
{
n_free (c_node[0]);
c_node[0] = new;
new = n_alloc (2 + new->len + c_node[pri]->len,
1000,
"%s, %s", new->string, c_node[pri]->string);
}
n_free (c_node[0]);
c_node[0] = new;
new = n_alloc (3 + new->len + c_node[aso]->len,
1000,
"%s, %s)", new->string, c_node[aso]->string);
}
n_free (c_node[0]);
break;
case C_FN4:
c_node -= 4;
new = n_alloc (c_node[0]->len + c_node[1]->len + c_node[2]->len + c_node[3]->len + strlen (f->fn_str) + 6,
1000,
F4,
f->fn_str,
c_node[0]->string,
c_node[1]->string,
c_node[2]->string,
c_node[3]->string);
n_free (c_node[0]);
n_free (c_node[1]);
n_free (c_node[2]);
n_free (c_node[3]);
break;
case C_ERR:
tmp_str = (char *) expr + jumpto;
expr++;
new = n_alloc (strlen (tmp_str) + 1, 1000, tmp_str);
/* bcopy((VOIDSTAR)expr,(VOIDSTAR)&tmp_str,sizeof(char *));
expr+=sizeof(char *);
new=n_alloc(strlen(tmp_str)+1,1000,f->fn_str,tmp_str); */
break;
case C_FLT:
bcopy ((VOIDSTAR) expr, (VOIDSTAR) & tmp_flt, sizeof (double));
expr += sizeof (double);
new = n_alloc (20, 1000, f->fn_str, tmp_flt);
new->len = strlen (new->string);
break;
case C_INT:
bcopy ((VOIDSTAR) expr, (VOIDSTAR) & tmp_lng, sizeof (long));
expr += sizeof (long);
new = n_alloc (20, 1000, f->fn_str, tmp_lng);
new->len = strlen (new->string);
break;
case C_VAR:
bcopy ((VOIDSTAR) expr, (VOIDSTAR) & v, sizeof (struct var *));
expr += sizeof (struct var *);
new = n_alloc (strlen (v->var_name) + 1,
1000,
f->fn_str, v->var_name);
break;
default:
panic ("Bad decompile %d", f->fn_comptype);
}
*c_node++ = new;
if (c_node == &the_line[line_alloc])
{
line_alloc *= 2;
the_line = ck_realloc (the_line, line_alloc * sizeof (struct pr_node *));
c_node = &the_line[line_alloc / 2];
}
if (*expr)
goto next_byte;
/* if(c_node != &the_line[1]) {
io_error_msg("%d values on decompile stack!",c_node - the_line);
return the_line[0];
} */
new = *--c_node;
/* free(the_line); */
return new;
}
/* Actual entry points to this file */
/* decomp(row, col, cell) returns a string that can be byte_compiled to create
cell->formula decomp_free() frees up the allocated string */
#if __STDC__
char *
decomp (CELLREF r, CELLREF c, CELL *cell)
#else
char *
decomp (r, c, cell)
CELLREF r;
CELLREF c;
CELL *cell;
#endif
{
struct pr_node *ret;
char *str;
extern char *bname[];
if (!cell)
return "";
decomp_row = r;
decomp_col = c;
if (cell->cell_formula == 0)
{
switch (GET_TYP (cell))
{
case 0:
str = ck_malloc (1);
str[0] = '\0';
break;
case TYP_FLT:
str = strdup (flt_to_str (cell->cell_flt));
break;
case TYP_INT:
str = ck_malloc (20);
sprintf (str, "%ld", cell->cell_int);
break;
case TYP_STR:
str = strdup (backslash_a_string (cell->cell_str, 1));
break;
case TYP_BOL:
str = strdup (bname[cell->cell_bol]);
break;
case TYP_ERR:
str = strdup (ename[cell->cell_bol]);
break;
default:
str = 0;
#ifdef TEST
panic ("Unknown type %d in decomp", GET_TYP (cell));
#endif
}
save_decomp = (VOIDSTAR) str;
return str;
}
else
ret = byte_decompile (cell->cell_formula);
save_decomp = (VOIDSTAR) ret;
return &(ret->string[0]);
}
#ifdef __STDC__
void
decomp_free (void)
#else
void
decomp_free ()
#endif
{
#ifdef TEST
if (!save_decomp)
panic ("No save decomp");
n_free (save_decomp);
save_decomp = (VOIDSTAR) 0;
#else
n_free (save_decomp);
#endif
}
/* This takes a string and returns a backslashed form suitable for printing.
Iff add_quote is true, it'll add "s at the beginning and end.
Note that this returns a pointer to a static area that is overwritten with
each call. . .
*/
#ifdef __STDC__
char *
backslash_a_string (char *string, int add_quote)
#else
char *
backslash_a_string (string, add_quote)
char *string;
int add_quote;
#endif
{
char *pf;
char *pt;
int ch;
int size;
int len;
static char *cbuf;
static int s_cbuf;
#define ALLOC_PT() \
len=strlen(pf); \
size=pf-string; \
if(s_cbuf<3+size+4*len) { \
s_cbuf=3+size+4*len; \
cbuf= (cbuf) ? ck_realloc(cbuf,s_cbuf) : ck_malloc(s_cbuf); \
} \
if(size) \
bcopy(string,cbuf,size); \
pt=cbuf+size; \
pt = 0;
pf = string;
if (add_quote)
{
ALLOC_PT ()
* pt++ = '"';
}
for (; *pf; pf++)
{
ch = *pf;
if (ch >= ' ' && ch <= '~' && ch != '\\' && (ch != '"' || !add_quote))
{
if (pt)
*pt++ = ch;
continue;
}
if (!pt)
{
ALLOC_PT ()
}
if (ch == '\\')
{
*pt++ = '\\';
*pt++ = '\\';
}
else if (ch == '"')
{
*pt++ = '\\';
*pt++ = ch;
}
else
{
*pt++ = '\\';
*pt++ = ((ch >> 6) & 0x3) + '0';
*pt++ = ((ch >> 3) & 0x7) + '0';
*pt++ = (ch & 0x7) + '0';
}
}
if (add_quote)
*pt++ = '"';
if (pt)
{
*pt++ = '\0';
return cbuf;
}
return string;
}
#ifdef TEST
void
dbg_print_formula (expr)
unsigned char *expr;
{
unsigned char byte;
struct function *f;
double tmp_flt;
char *tmp_str;
long tmp_int;
struct var *v;
struct rng rng;
char *buf;
unsigned jumpto;
extern char print_buf[];
extern char *strcpy ();
if (!expr)
return;
strcpy (print_buf, "Formula: ");
buf = print_buf + 9;
while (*expr)
{
byte = *expr++;
if (byte < USR1)
f = &the_funs[byte];
else if (byte < SKIP)
{
tmp_int = *expr++;
f = &usr_funs[byte - USR1][tmp_int];
}
else
f = &skip_funs[byte - SKIP];
if (f->fn_argn & X_J)
jumpto = *expr++;
else if (f->fn_argn & X_JL)
{
jumpto = expr[0] + ((unsigned) (expr[1]) << 8);
expr += 2;
}
else
jumpto = 0;
switch (GET_COMP (f->fn_comptype))
{
case C_IF:
sprintf (buf, " if%d.%u", byte, jumpto);
break;
case C_ANDOR:
sprintf (buf, " andor%d.%u", byte, jumpto);
break;
case C_ERR:
tmp_str = (char *) (expr + jumpto);
byte = *expr++;
sprintf (buf, " err%d.%p(%s)", byte, tmp_str, tmp_str);
break;
case C_FLT:
bcopy ((VOIDSTAR) expr, (VOIDSTAR) & tmp_flt, sizeof (double));
expr += sizeof (double);
sprintf (buf, " flt.%.15g", tmp_flt);
break;
case C_INT:
bcopy ((VOIDSTAR) expr, (VOIDSTAR) & tmp_int, sizeof (long));
expr += sizeof (long);
sprintf (buf, " int.%ld", tmp_int);
break;
case C_STR:
tmp_str = (char *) (expr + jumpto);
sprintf (buf, " str.%p.%s", tmp_str, tmp_str);
break;
case C_VAR:
bcopy ((VOIDSTAR) expr, (VOIDSTAR) & v, sizeof (struct var *));
expr += sizeof (struct var *);
sprintf (buf, " var.%p.%s", v, v->var_name);
break;
case C_CELL:
sprintf (buf, " ref%d.%u.%u", byte, GET_ROW (expr), GET_COL (expr));
expr += EXP_ADD;
break;
case C_RANGE:
GET_RNG (expr, &rng);
sprintf (buf, " rng%d.%u-%u,%u-%u", byte, rng.lr, rng.hr, rng.lc, rng.hc);
expr += EXP_ADD_RNG;
break;
case C_FN0:
case C_FN0X:
case C_FN1:
case C_FN2:
case C_FN3:
case C_FN4:
case C_UNA:
case C_INF:
sprintf (buf, " fun%d.%s.%p", byte, f->fn_str, f->fn_fun);
break;
case C_FNN:
sprintf (buf, " funn%d.%s.%p.%d", byte, f->fn_str, f->fn_fun, *expr++);
break;
case C_CONST:
sprintf (buf, " const%s", f->fn_str);
break;
case C_SKIP:
sprintf (buf, " skip.%d", jumpto);
break;
case 0:
sprintf (buf, " ???%d", byte);
break;
default:
io_error_msg ("Unknown decompile type %d", f->fn_comptype);
}
buf += strlen (buf);
}
io_text_line (print_buf);
}
#endif